import Router from 'koa-router';
import mongoose from 'mongoose';
import assert from 'assert';
import _ from 'lodash';
import log4js from 'koa-log4';
import pmx from 'pmx';
import messageHandler from '../handler/messageHandler';
import config from '../../config';
import robots, { tags } from '../robots';

const User = mongoose.model('User');
const Channel = mongoose.model('Channel');
const Queue = mongoose.model('Queue');
const logger = log4js.getLogger('Internal');
const probe = pmx.probe();

// The counter will start at 0
const counter = probe.counter({
  name: 'WeChat Income',
});
/**
 * 内部接口调用
 */
const router = new Router({
  prefix: '/api/internals',
});

router.use((ctx, next) => {
  // accept apiKey, apikey...
  assert.equal(ctx.request.headers.apikey, config.API_KEY, 'api_key_not_valid');
  return next();
});

async function ensureSocialUser(jiuquId, fromSocialId, userInfoRaw) {
  assert(jiuquId || fromSocialId, 'jiuquId_or_fromSocialId_should_exist');

  let user = jiuquId
    ? await User.findStudentByJiuquId(jiuquId)
    : await User.findAnonymousStudent(fromSocialId);

  if (!user && jiuquId) user = await User.findAnonymousStudent(fromSocialId);
  const userInfo = userInfoRaw || {
    id: fromSocialId,
    username: fromSocialId,
    nickname: fromSocialId,
    headImgUrl: null,
    mobileSuffix: null,
  };

  if (!user) {
    user = await User.ensureJiuQuUser(userInfo, 'student');
    user.userSocialIds = [fromSocialId];
    await user.save();
  } else if (jiuquId && user.isAnonymous()) {
    user.jiuquId = `Student:${userInfo.id}`;
    user.username = userInfo.username || fromSocialId;
    user.nickname = userInfo.nickname || fromSocialId;
    user.headImgUrl = userInfo.headImgUrl || null;

    await user.save();
  }

  // teacher/student 应该有且只有一个channel
  const userChannelId = user.channels[0];
  assert(userChannelId, 'userChannelNotExist');

  if (!user.isAnonymous() && userInfo.mobileSuffix) {
    const channel = await Channel.findById(userChannelId);
    const bestChannelName = `${user.nickname || user.username}:${userInfo.mobileSuffix}`;
    if (channel.name !== bestChannelName) {
      const duplicate = await Channel.findOne({ name: bestChannelName });
      channel.name = duplicate ? bestChannelName + fromSocialId.slice(-4) : bestChannelName;
      channel.save();
    }
  }

  return {
    userChannelId,
    user,
  };
}

async function ensureSocialUserService(user, service) {
  if (service) {
    user.service = service; // eslint-disable-line
    user.save();
  }
}

/**
 * type input = {
 *  body : "232323"
 *  mention : ""
 *  subType : "text"
 *  fromSocialId: "2223333"
 * }
 */
router.post('/message', async (ctx) => {
  const {
    fromSocialId, input, userInfo, service,
  } = ctx.request.body;
  const jiuquId = _.get(userInfo, 'id');

  const { user, userChannelId } = await ensureSocialUser(jiuquId, fromSocialId, userInfo);

  await ensureSocialUserService(user, service);

  input.fromSocialId = fromSocialId;
  counter.inc();
  await messageHandler.post(userChannelId, user, input);

  ctx.body = {
    ok: true,
  };
});

router.post('/queue', async (ctx) => {
  const { fromSocialId, userInfo, type } = ctx.request.body;
  const jiuquId = _.get(userInfo, 'id');

  logger.log('Receive queue JiuquId %s fromSocialId %s', jiuquId, fromSocialId);
  const { userChannelId } = await ensureSocialUser(jiuquId, fromSocialId, userInfo);

  const exist = await Queue.findOne({
    type,
    jiuquId,
  });

  assert(!exist, '数据已存在');

  const queue = new Queue({
    type,
    jiuquId,
    fromSocialId,
    resolved: false,
    targetChannel: userChannelId,
  });

  await queue.save();

  ctx.body = {
    ok: true,
  };
});

router.post('/urgentReplacement', async (ctx) => {
  const replacement = ctx.request.body;
  const expectFields = [
    'fromTeacherId',
    'toTeacherId',
    'reason',
    'roomId',
    'beginAt',
    'lessonId',
    'lessonId',
  ];
  expectFields.forEach(field => assert(replacement[field], `${field}_should_exist`));

  robots.dispatchInternalEvent(tags.URGENT_REPLACEMENT, replacement);

  ctx.body = {
    ok: true,
  };
});

router.post('/forwardMessage', async (ctx) => {
  const { userInfo, input = {} } = ctx.request.body;
  const jiuquId = _.get(userInfo, 'id');

  const { subType, body } = input;

  assert(subType, 'message_type_should_exist');
  assert(body, 'message_body_should_exist');

  assert(jiuquId, 'jiuquId_should_exist');
  const user = await User.findOne({ jiuquId: `Student:${jiuquId}` });
  assert(user, 'user_not_exist');
  const userChannel = _.head(user.channels);
  assert(userChannel, 'userChannel_not_exist');

  const systemRobot = await User.getSystemRobot();

  await messageHandler.post(userChannel, systemRobot, {
    mention: [user.id],
    subType,
    body: subType === 'text' ? `@${user.nickname}: ${body}` : body,
  });

  ctx.body = {
    ok: true,
  };
});

export default router;
